package com.jackstraw.jack_base.datasource.common.aspect.aop;


import com.jackstraw.jack_base.datasource.common.aspect.annotation.DataSourceNameCut;
import com.jackstraw.jack_base.datasource.common.contextholder.DataSourceContextHolder;
import com.jackstraw.jack_base.datasource.common.entity.enums.DataSourceTypeEnum;
import com.jackstraw.jack_base.util.AspectUtil;
import com.jackstraw.jack_base.util.StringUtil;
import com.jackstraw.jack_base.util.exception.BadConfigException;
import com.jackstraw.jack_base.util.exception.BadException;
import com.jackstraw.jack_base.util.exception.enums.ExceptionEnum;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 数据源名称切面类
 */
@Slf4j
@Aspect
@Component
public class DataSourceNameAspect implements Ordered {


    /**
     * 导入配置文件
     */
    @Autowired
    private StandardEnvironment standardEnvironment;


    @Pointcut("@within(com.jackstraw.jack_base.datasource.common.aspect.annotation.DataSourceNameCut)" +
            "|| execution(* *..service.*.*(..))")
    public void defaultPointCut() {

    }


    @Around("defaultPointCut()")
    public Object dbDefaultCutByAround(ProceedingJoinPoint joinPoint) {
        long currentTimeMillis = System.currentTimeMillis();
        //获取Method
        Method method = AspectUtil.getMethod(joinPoint);
        // 获得目标方法名
        String methodName = method.getName();
        //获取代理的对象
        Class aClass = AspectUtil.getClass(joinPoint);
        String className = aClass.getName();
        if (StringUtil.StringUtilsBylang3.isEmpty(className) || StringUtil.StringUtilsBylang3.isEmpty(methodName)) {
            log.error("DataSourceName切面异常，无法获取切面类名称或切面方法名称");
            throw new BadConfigException(BadException.bulidErrorCode(ExceptionEnum.COMMON_DATASOURCE, "009"),
                    "DataSourceName切面异常，无法获取切面类名称或切面方法名称");
        }

        if (!aClass.isAnnotationPresent(DataSourceNameCut.class)) {
            try {
                return proceed(joinPoint);
            } catch (Throwable e) {
                log.error("AOP环绕通知【时间戳为:{}】=========={}#{}方法执行异常", currentTimeMillis, className, methodName);
                throw new BadConfigException(BadException.bulidErrorCode(ExceptionEnum.COMMON_DATASOURCE, "011"),
                        "AOP环绕通知【时间戳为:{}】=========={}#{}方法执行异常", e, currentTimeMillis, className, methodName);
            }
        } else {
            log.debug("AOP环绕通知【时间戳为:{}】=========={}#{}方法执行开始", currentTimeMillis, className, methodName);
            DataSourceNameCut dataSourceNameCut = (DataSourceNameCut) aClass.getAnnotation(DataSourceNameCut.class);
            DataSourceTypeEnum dataSourceTypeEnum = dataSourceNameCut.dataSourceTypeEnum();
            String dataSourceName = dataSourceNameCut.dataSourceName();
            /**
             * 获取配置文件内容
             */
            dataSourceName = this.standardEnvironment.resolvePlaceholders(dataSourceName);

            //先获取旧的名称
            String dataSourceNameByOld = DataSourceContextHolder.getDataSourceName(dataSourceTypeEnum);

            //设置数据源名称
            DataSourceContextHolder.setDataSourceName(dataSourceTypeEnum, dataSourceName);
            try {
                Object proceed = proceed(joinPoint);
                return proceed;
            } catch (Throwable e) {
                log.error("AOP环绕通知【时间戳为:{}】=========={}#{}方法执行异常", currentTimeMillis, className, methodName);
                throw new BadConfigException(BadException.bulidErrorCode(ExceptionEnum.COMMON_DATASOURCE, "011"),
                        "AOP环绕通知【时间戳为:{}】=========={}#{}方法执行异常", e, currentTimeMillis, className, methodName);
            } finally {
                log.debug("AOP环绕通知【时间戳为:{}】=========={}#{}方法执行结束", currentTimeMillis, className, methodName);
                DataSourceContextHolder.clearDataSourceName(dataSourceTypeEnum);
                //如果拿到的旧名称不为null，就放回去
                if (StringUtil.StringUtilsBylang3.isNotEmpty(dataSourceNameByOld)) {
                    DataSourceContextHolder.setDataSourceName(dataSourceTypeEnum, dataSourceNameByOld);
                }
            }
        }
    }


    public Object proceed(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取参数
        Object[] args = joinPoint.getArgs();
        Object proceed = null;
        if (args == null || args.length == 0) {
            proceed = joinPoint.proceed();
        } else {
            proceed = joinPoint.proceed(args);
        }
        return proceed;
    }

    @Override
    public int getOrder() {
        return -1;
    }
}
